package org.rc.task;

import com.google.appengine.api.taskqueue.Queue;
import com.google.appengine.api.taskqueue.QueueFactory;
import com.google.appengine.api.taskqueue.TaskOptions;
import com.googlecode.objectify.Key;
import org.rc.dao.GenericDao;
import org.rc.dao.RaceDao;
import org.rc.dao.ResultDao;
import org.rc.model.Race;
import org.rc.model.Result;
import org.rc.model.Statistics;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

import static com.google.appengine.api.taskqueue.TaskOptions.Builder.withUrl;

/**
 * Delete a race and all results, dont delete Athletes
 * @author dokeeffe
 */
public class DeleteRaceAndResultsTask extends Task {

    private static final Logger LOGGER = LoggerFactory.getLogger(DeleteRaceAndResultsTask.class);
    public ResultDao resultDao = new ResultDao();
    public RaceDao raceDao = new RaceDao();
    public GenericDao<Statistics> statsDao = new GenericDao<Statistics>(Statistics.class);


    /**
     * Run the delete races and results task. Deletes all races and results for the "raceid" in the parameter map
     * @param parameterMap
     */
    @Override
    public void run(Map parameterMap) {
        long startTime = System.currentTimeMillis();
        String raceIdString = ((String[]) parameterMap.get("raceid"))[0];
        Long id = null;
        try {
            id=Long.parseLong(raceIdString);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException(e);
        }
        Race toDelete = raceDao.get(id);
        Integer noOfResults = toDelete.getNumberOfResults();
        Iterable<Key<Result>> allKeys = resultDao.ofy().query(Result.class).filter("race",toDelete).fetchKeys();

        LOGGER.info("Starting to delete results for race " + raceIdString);
        int count = 0;
        for(Key<Result> key : allKeys) {
            resultDao.delete(key);
            count++;
            if(timeUp(startTime)) {
                resubmit(raceIdString);
                return;
            }
        }
        LOGGER.info("deleted results count " + count);
        raceDao.delete(toDelete);
        updateSystemStats(noOfResults);
    }

    /**
     * Update the system statstics with the deleted results.
     * @param noOfResults
     */
    private void updateSystemStats(Integer noOfResults) {
        Statistics stats = statsDao.getAll().get(0);
        stats.setNumberOfRaces(stats.getNumberOfRaces()-1);
        if(noOfResults!=null) {
            stats.setNumberOfResults(stats.getNumberOfResults()-noOfResults);
        }
        statsDao.put(stats);
    }

    /**
     * Check if processing time is up
     * @param startTime
     * @return
     */
    private boolean timeUp(long startTime) {
        if (System.currentTimeMillis() - startTime > LIMIT_MILLIS) {
            return true;
        }
        return false;
    }

    /**
     * Resubmit another task
     * @param raceid
     */
    private void resubmit(String raceid) {
        LOGGER.info("Resubmitting for race " + raceid);
        Queue queue = QueueFactory.getDefaultQueue();
        queue.add(withUrl("/admin?task=" + getTaskName() + "&raceid="+raceid).method(TaskOptions.Method.GET));
    }

    @Override
    public String getUiName() {
        return "Delete Race and Results";
    }

}
